#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <sw/redis++/redis++.h>
#include <chrono>
#include <thread>

#include "util.hpp"

/*
1. setnx 和 setxx 都需要通过 expire 的第四个参数来设置，并且过期时间就算没有，也要填 0

2. mset 函数，有两个版本
    1. void mset(std::initializer_list<T> il), 初始化列表里面的每个元素都是 pair
    2. void mset(Input first, Output end)
*/

using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::unordered_map;
using std::vector;

using sw::redis::Redis;
using sw::redis::StringView;
using namespace std::chrono_literals;

void SetUpdate(Redis& redis) {
    redis.flushdb();
    redis.set("key", "value");

    auto value = redis.get("key");
    cout << "value = " << value.value() << endl;

    cout << "修改之后" << endl;

    redis.set("key", "new_value");
    value = redis.get("key");
    cout << "value = " << value.value() << endl;
}

void Expire(Redis& redis) {
    redis.flushdb();

    // 顺手设置超时时间
    redis.set("key", "value", 10s);

    std::this_thread::sleep_for(2s);

    long long time = redis.ttl("key");

    cout << "过期时间 = " << time;
}

// 使用 set 并指定 nx | xx
void Nxxx(Redis& redis) {
    redis.flushdb();

    redis.set("key", "hhhhhhh");

    // 这里必须搭配过期时间来使用
    // 这里计算不需要设置过期时间，也要设置
    // redis.set("key", "value", 0s, sw::redis::UpdateType::NOT_EXIST);
    redis.set("key", "value", 0s, sw::redis::UpdateType::EXIST);

    auto value = redis.get("key");
    if (value) {
        cout << "value = " << value.value() << endl;
    }
    else {
        cout << "Key 不存在" << endl;
    }
}

void MgetMset(Redis& redis) {
    redis.flushdb();

    // mset 第一种写法
    // redis.mset({std::make_pair("key1", "value1"), std::make_pair("key2", "value2"), std::make_pair("key3", "value3")});
    // mset 第二种写法
    vector<std::pair<string, string>> pairs = {
        {"key1", "value1"},
        {"key2", "value2"},
        {"key3", "value3"}
    };
    redis.mset(pairs.begin(), pairs.end());

    auto value = redis.get("key1");
    cout << "key1 = " << value.value() << endl;

    // 然后时 mget, 因为获取到的数据可能为空, 所以需要使用 OptionalString
    vector<sw::redis::OptionalString> result;
    auto it = std::back_inserter(result);
    redis.mget({"key1", "key2", "key3"}, it);
    PrintOp(result);
}

void Range(Redis& redis) {
    redis.flushdb();

    redis.set("key", "public static void main(String[] args)");
    // 直接用 string 接收，如果为空，会返回字符串
    string result = redis.getrange("key", 7, 12);
    auto value = redis.get("key");
    cout << "getrange 获取的 value = " << result << endl;

    redis.setrange("key", 2, "xxxxx");
    value = redis.get("key");

    cout << "setrange 之后的 value = " << value.value() << endl;
}

void IncrBy(Redis& redis) {
    redis.flushdb();
    redis.set("key", "100");

    long long after = redis.incr("key");

    auto result = redis.get("key");

    cout << "after = " << after << endl;
    cout << "result = " << result.value() << endl;

    after = redis.decr("key");

    result = redis.get("key");

    cout << "after = " << after << endl;
    cout << "result = " << result.value() << endl;

    after = redis.incrby("key", 100);
    result = redis.get("key");

    cout << "after = " << after << endl;
    cout << "result = " << result.value() << endl;
}

int main() {
    Redis redis("tcp://127.0.0.1:6379");

    SetUpdate(redis);

    // Expire(redis);

    Nxxx(redis);

    MgetMset(redis);

    Range(redis);

    IncrBy(redis);
    return 0;
}